﻿using System;

namespace DirectoryCleaner
{
    /// <summary>
    /// Parses the command line input to DirectoryCleaner.
    /// </summary>
    public sealed class Parser
    {
        private readonly string[] args;
        private string[] extensions;
        private string directory;

        /// <summary>
        /// Creates and initializes a new <see cref="Parser"/> instance.
        /// </summary>
        /// <param name="args">Command line arguments.</param>
        /// <exception cref="ArgumentNullException">
        /// <para>
        /// <strong>args</strong> is <strong>null</strong>;
        /// </para>
        /// <para>
        /// or
        /// </para>
        /// <para>
        /// no flags have been specified.
        /// </para>
        /// </exception>
        public Parser(string[] args)
        {
            // verify preconditions of type initialization
            if (args == null)
            {
                throw new ArgumentNullException("args");
            }
            else if (args.Length < 1)
            {
                throw new ArgumentException("Please specify some flag arguments.");
            }

            this.args = args;
        }

        /// <summary>
        /// Parses the command line arguments.
        /// </summary>
        /// <exception cref="ArgumentException">
        /// <para>
        /// input is incorrectly formatted;
        /// </para>
        /// <strong>or</strong>
        /// <para>
        /// flag is unrecognized;
        /// </para>
        /// <para>
        /// or
        /// </para>
        /// <para>
        /// flag /preserve was not specified.
        /// </para>
        /// </exception>
        public void Parse()
        {
            foreach (string arg in args)
            {
                int flagEnd = arg.IndexOf(':');
                string flag = arg.Substring(0, flagEnd + 1);

                // verify that the input structure is correct
                if (flagEnd < 0)
                {
                    throw new ArgumentException("Incorrectly structured input.");
                }

                // verify which flag we have
                if (flag == "/preserve:")
                {
                    ValidateFlagArguments(flag, flagEnd, arg);
                    extensions = arg.Substring(flagEnd + 1).Split(';');
                }
                else if (flag == "/dir:")
                {
                    ValidateFlagArguments(flag, flagEnd, arg);
                    directory = arg.Substring(flagEnd + 1);
                }
                else
                {
                    // what flag is this?!
                    throw new ArgumentException(string.Format("Unrecognized flag: {0}", flag));
                }
            }

            // determine whether a critical flag was omitted
            if (extensions == null)
            {
                throw new ArgumentException("Flag: /preserve: must be specified."); 
            }
        }

        /// <summary>
        /// Checks to make sure a flag has some arguments.
        /// </summary>
        /// <remarks>
        /// All flags used in Directory Cleaner have args.
        /// </remarks>
        /// <param name="flag">Flag.</param>
        /// <param name="flagEnd">Index where flag definition ends.</param>
        /// <param name="arg">Current argument in full.</param>
        /// <exception cref="ArgumentException"><strong>flag</strong> has no arguments.</exception>
        private void ValidateFlagArguments(string flag, int flagEnd, string arg)
        {
            if (flagEnd + 1 == arg.Length)
            {
                throw new ArgumentException(string.Format("Please specify args for flag: {0}", flag));
            }
        }

        /// <summary>
        /// Gets the list of file extensions.
        /// </summary>
        public string[] Extensions
        {
            get { return extensions; }
        }

        /// <summary>
        /// Gets the directory specified to clean.
        /// </summary>
        public string Directory
        {
            get { return directory; }
        }
    }
}
